package cn.aitrox.ry.service.anno.service.impl;

import cn.aitrox.ry.bean.CommonPageInfo;
import cn.aitrox.ry.bean.RespResult;
import cn.aitrox.ry.common.exception.CustomBizException;
import cn.aitrox.ry.common.interceptor.UserThreadLocal;
import cn.aitrox.ry.common.service.BaseService;
import cn.aitrox.ry.constant.CommonConstant;
import cn.aitrox.ry.enumtype.ProcessStatusEnum;
import cn.aitrox.ry.enumtype.RespCodeEnum;
import cn.aitrox.ry.service.anno.config.AnnoNacosProperties;
import cn.aitrox.ry.service.anno.dao.AnnoComponentDao;
import cn.aitrox.ry.service.anno.dao.AnnoFileHandlerInfoDao;
import cn.aitrox.ry.service.anno.dao.AnnoLesionResultDao;
import cn.aitrox.ry.service.anno.dao.AnnoLesionToolDao;
import cn.aitrox.ry.service.anno.dao.AnnoResultDao;
import cn.aitrox.ry.service.anno.dao.TaskCompanyDao;
import cn.aitrox.ry.service.anno.dao.TaskDao;
import cn.aitrox.ry.service.anno.dao.TaskSeriesDao;
import cn.aitrox.ry.service.anno.dao.TaskUserDao;
import cn.aitrox.ry.service.anno.dao.UserTaskDao;
import cn.aitrox.ry.service.anno.dto.task.AnnoUserDto;
import cn.aitrox.ry.service.anno.dto.task.ComponentDto;
import cn.aitrox.ry.service.anno.dto.task.LesionDto;
import cn.aitrox.ry.service.anno.dto.task.TaskDetailDto;
import cn.aitrox.ry.service.anno.dto.task.TaskDto;
import cn.aitrox.ry.service.anno.dto.task.in.AnnoSeriesDto;
import cn.aitrox.ry.service.anno.dto.task.in.AnnoSettingDto;
import cn.aitrox.ry.service.anno.dto.task.in.AnnoUserSettingDto;
import cn.aitrox.ry.service.anno.dto.task.in.BasicSettingDto;
import cn.aitrox.ry.service.anno.dto.task.in.TaskCreateInDto;
import cn.aitrox.ry.service.anno.dto.task.in.TaskEditInDto;
import cn.aitrox.ry.service.anno.dto.task.in.TaskSearchInDto;
import cn.aitrox.ry.service.anno.entity.AnnoComponentEntity;
import cn.aitrox.ry.service.anno.entity.AnnoFileHandlerInfoEntity;
import cn.aitrox.ry.service.anno.entity.AnnoLesionToolEntity;
import cn.aitrox.ry.service.anno.entity.TaskCompanyEntity;
import cn.aitrox.ry.service.anno.entity.TaskEntity;
import cn.aitrox.ry.service.anno.entity.TaskSeriesEntity;
import cn.aitrox.ry.service.anno.entity.TaskUserEntity;
import cn.aitrox.ry.service.anno.enumtype.FileHandlerBizTypeEnum;
import cn.aitrox.ry.service.anno.enumtype.anno.AnnoResultStatusEnum;
import cn.aitrox.ry.service.anno.enumtype.task.TaskStatusEnum;
import cn.aitrox.ry.service.anno.mq.produser.FileHandlerProduser;
import cn.aitrox.ry.service.anno.po.task.TaskAnnoCountInfoPo;
import cn.aitrox.ry.service.anno.po.task.TaskFindCondPo;
import cn.aitrox.ry.service.anno.po.task.TaskSeriesCountPo;
import cn.aitrox.ry.service.anno.service.FileHandlerInfoService;
import cn.aitrox.ry.service.anno.service.TaskService;
import cn.aitrox.ry.service.config.enumtype.ImageLayoutEnum;
import cn.aitrox.ry.service.config.enumtype.ImageTransferModeEnum;
import cn.aitrox.ry.service.dwh.dto.DwhImageDto;
import cn.aitrox.ry.service.dwh.dto.in.DwhImageQueryInDto;
import cn.aitrox.ry.service.dwh.feign.DwhImageFeign;
import cn.aitrox.ry.service.image.dto.image.in.ImageQueryInDto;
import cn.aitrox.ry.service.image.dto.image.out.ImageInfoOutDto;
import cn.aitrox.ry.service.image.enumtype.ImageGroupTypeEnum;
import cn.aitrox.ry.service.image.feign.ImageFeign;
import cn.aitrox.ry.util.ArrayUtil;
import cn.aitrox.ry.util.BeanUtil;
import cn.aitrox.ry.util.DateUtil;
import cn.aitrox.ry.util.JSONUtil;
import com.github.pagehelper.PageInfo;
import com.google.gson.JsonElement;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
public class TaskServiceImpl extends BaseService implements TaskService {

    @Autowired
    private TaskDao taskDao;

    @Autowired
    private TaskCompanyDao taskCompanyDao;

    @Autowired
    private TaskUserDao taskUserDao;

    @Autowired
    private AnnoLesionToolDao annoLesionToolDao;

    @Autowired
    private AnnoComponentDao annoComponentDao;

    @Autowired
    private TaskSeriesDao taskSeriesDao;

    @Autowired
    private AnnoLesionResultDao annoLesionResultDao;

    @Autowired
    private AnnoResultDao annoResultDao;

    @Autowired
    private UserThreadLocal userThreadLocal;

    @Autowired
    private FileHandlerProduser fileHandlerProduser;

    @Autowired
    private AnnoFileHandlerInfoDao fileHandlerInfoDao;

    @Autowired
    private UserTaskDao userTaskDao;

    @Autowired
    private AnnoNacosProperties annoNacosProperties;

    @Autowired
    @Lazy
    private DwhImageFeign dwhImageFeign;

    @Autowired
    private FileHandlerInfoService fileHandlerInfoService;

    @Autowired
    @Lazy
    private ImageFeign imageFeign;

    @Override
    public CommonPageInfo<TaskDto> search(TaskSearchInDto input) {
        TaskFindCondPo cond = new TaskFindCondPo();
        BeanUtil.copy(input, cond);
        if (StringUtils.isNotEmpty(cond.getKeyword())) {
            if (NumberUtils.isDigits(cond.getKeyword())) {
                try {
                    cond.setId(Integer.parseInt(cond.getKeyword()));
                } catch (NumberFormatException e) {
                }
            }
            String likeKeword = "%" + cond.getKeyword() + "%";
            cond.setLikeName(likeKeword);
            cond.setLikeCreateUserName(likeKeword);
        }

        PageInfo<TaskEntity> pageInfo = taskDao.searchByCustom(input.getPage(), input.getPageSize(), cond);

        if (ArrayUtil.isEmpty(pageInfo.getList())) {
            return new CommonPageInfo(0, 0, null);
        }

        List<Integer> taskIdList = pageInfo.getList().stream().map(TaskEntity::getId).collect(Collectors.toList());

        List<TaskCompanyEntity> taskCompanyList = taskCompanyDao.findByTaskIds(taskIdList);
        Map<Integer, List<TaskCompanyEntity>> taskCompantMap = taskCompanyList.stream().collect(Collectors.groupingBy(TaskCompanyEntity::getTaskId));

        // 查询任务序列数量
        List<TaskSeriesCountPo> tsCountList = taskSeriesDao.findTaskSeriesCountByTaskIds(taskIdList);
        Map<Integer, Integer> taskSeriesCountMap = tsCountList.stream().collect(Collectors.toMap(TaskSeriesCountPo::getTaskId, TaskSeriesCountPo::getSeriesCount));

        List<TaskAnnoCountInfoPo> annoCountInfoPoList = annoResultDao.findAnnoCountInfoByTaskIdsStatus(taskIdList, AnnoResultStatusEnum.SUBMIT.getStatus(), AnnoResultStatusEnum.DISCARD.getStatus());
        Map<Integer, TaskAnnoCountInfoPo> annoCountInfoMap = annoCountInfoPoList.stream().collect(Collectors.toMap(TaskAnnoCountInfoPo::getTaskId, x -> x));

        List<TaskDto> taskList = pageInfo.getList().stream().map(x -> {
            return packTask(x, taskCompantMap.get(x.getId()), taskSeriesCountMap.get(x.getId()), annoCountInfoMap.get(x.getId()));
        }).collect(Collectors.toList());

        return new CommonPageInfo(pageInfo.getTotal(), pageInfo.getPages(), taskList);
    }

    @Transactional
    @Override
    public RespResult statusEdit(Integer id, Integer status) {
        TaskStatusEnum statusEnum = TaskStatusEnum.getEnumByStatus(status);
        if (null == statusEnum) {
            return RespResult.error("不支持修改的状态");
        }

        TaskEntity task = taskDao.findById(id);
        if (null == task) {
            return RespResult.error(RespCodeEnum.NOT_EXIST);
        }

        switch (statusEnum) {
            case PROCESSING:
                // 校验影像转换是否完成
                RespResult respResult = this.validImageTransfer(task);
                if (!respResult._isOk()) {
                    return respResult;
                }
                // 大图任务需要下载大图文件到本地
                this.triggerDownloadImage(task);
                taskDao.updateStatusById(id, TaskStatusEnum.PROCESSING.getStatus());
                break;
            case TERMINATE:
                // 触发用户针对任务的状态为已终结
                userTaskDao.terminate(id);
                taskDao.updateStatusById(id, TaskStatusEnum.TERMINATE.getStatus());
                break;
            default:
                return RespResult.error("不支持修改的状态");
        }
        return RespResult.ok();
    }

    @Override
    public TaskDetailDto read(Integer id) {
        TaskEntity taskEntity = taskDao.findById(id);
        if (null == taskEntity) {
            return null;
        }
        List<TaskCompanyEntity> taskCompanyEntityList = taskCompanyDao.findByTaskId(id);

        List<TaskUserEntity> taskUserEntityList = taskUserDao.findByTaskId(id);

        List<AnnoLesionToolEntity> annoLesionToolEntityList = annoLesionToolDao.findByTaskId(id);

        List<AnnoComponentEntity> annoComponentEntityList = annoComponentDao.findByTaskId(id);

        List<TaskSeriesEntity> taskSeriesEntityList = taskSeriesDao.findByTaskId(id);

        return packTaskDetail(taskEntity, taskCompanyEntityList, taskUserEntityList, annoLesionToolEntityList, annoComponentEntityList, taskSeriesEntityList);
    }

    @Transactional
    @Override
    public RespResult<TaskDto> create(TaskCreateInDto input) {
        // 校验任务名称是否存在
        Boolean nameExisted = this.taskNameExisted(null, input.getBasicSetting().getName());
        if (nameExisted) {
            return RespResult.secByError(RespCodeEnum.EXISTED.getCode(), "任务名称已存在");
        }

        TaskEntity taskEntity = this.packUserEntity(input);
        taskDao.insertSelective(taskEntity);

        List<ComponentDto> seriesFcList = null != input.getAnnoSetting() ? input.getAnnoSetting().getSeriesFcList() : null;
        List<LesionDto> lesionList = null != input.getAnnoSetting() ? input.getAnnoSetting().getLesionList() : null;
        List<AnnoUserDto> annoUserList = null != input.getAnnoUserSetting() ? input.getAnnoUserSetting().getAnnoUserList() : null;
        List<AnnoSeriesDto> annoSeriesList = null != input.getDataSetting() ? input.getDataSetting().getAnnoSeriesList() : null;

        List<AnnoComponentEntity> seriesComponentEntityList = this.packSeriesComponentEntityList(taskEntity.getId(), seriesFcList);
        List<AnnoComponentEntity> imageComponentEntityList = this.packImageComponentEntityList(taskEntity.getId(), lesionList);
        List<AnnoLesionToolEntity> annoLesionToolEntityList = this.packAnnoLesionToolEntityList(taskEntity.getId(), lesionList);
        List<TaskCompanyEntity> taskCompanyEntityList = this.packTaskCompanyEntityList(taskEntity.getId(), annoUserList);

        List<TaskSeriesEntity> taskSeriesEntityList = this.packTaskSeriesEntityList(taskEntity.getId(), annoSeriesList);


        if (!ArrayUtil.isEmpty(taskCompanyEntityList)) {
            taskCompanyDao.batchSave(taskCompanyEntityList);
            taskCompanyEntityList = taskCompanyDao.findByTaskId(taskEntity.getId());
            List<TaskUserEntity> taskUserEntityList = this.packTaskUserEntityList(annoUserList, taskCompanyEntityList);
            taskUserDao.batchSave(taskUserEntityList);
        }

        List<AnnoComponentEntity> annoComponentEntityList = new ArrayList<>();
        if (!ArrayUtil.isEmpty(seriesComponentEntityList)) {
            annoComponentEntityList.addAll(seriesComponentEntityList);
        }
        if (!ArrayUtil.isEmpty(imageComponentEntityList)) {
            annoComponentEntityList.addAll(imageComponentEntityList);
        }

        if (!ArrayUtil.isEmpty(annoLesionToolEntityList)) {
            annoLesionToolDao.batchSave(annoLesionToolEntityList);
        }
        if (!ArrayUtil.isEmpty(annoComponentEntityList)) {
            annoComponentDao.batchSave(annoComponentEntityList);
        }
        if (!ArrayUtil.isEmpty(taskSeriesEntityList)) {
            taskSeriesDao.batchSave(taskSeriesEntityList);
        }

        TaskDto task = new TaskDto();
        task.setId(taskEntity.getId());
        return RespResult.ok(task);
    }

    /**
     * 所有条件删除，必须写sql进行删除，不允许使用插件api
     *
     * @param input
     * @return
     */
    @Transactional
    @Override
    public RespResult edit(TaskEditInDto input) {
        TaskEntity taskEntity = taskDao.findById(input.getId());
        if (null == taskEntity) {
            return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "任务不存在");
        }
        // 校验任务名称是否存在
        Boolean nameExisted = this.taskNameExisted(input.getId(), input.getBasicSetting().getName());
        if (nameExisted) {
            return RespResult.secByError(RespCodeEnum.EXISTED.getCode(), "任务名称已存在");
        }

        TaskEntity taskEntityUpdate = this.packUserEntity(input);
        taskEntityUpdate.setId(taskEntity.getId());
        taskEntityUpdate.setStatus(null);
        taskDao.updateByIdSelective(taskEntityUpdate);

        // []代表清空，null代表未修改
        // 先删除，再插入

        if (null != input.getAnnoSetting()) {
            List<AnnoLesionToolEntity> annoLesionToolEntityList = null;
            List<AnnoComponentEntity> annoComponentEntityList = new ArrayList<>();

            Boolean deleteAnnoComp = false;
            Boolean deleteAnnoLesionTool = false;

            if (null != input.getAnnoSetting().getSeriesFcList()) {
                deleteAnnoComp = true;
                List<AnnoComponentEntity> seriesComponentEntityList = this.packSeriesComponentEntityList(taskEntity.getId(), input.getAnnoSetting().getSeriesFcList());
                if (!ArrayUtil.isEmpty(seriesComponentEntityList)) {
                    annoComponentEntityList.addAll(seriesComponentEntityList);
                }
            }

            if (null != input.getAnnoSetting().getLesionList()) {
                deleteAnnoLesionTool = true;
                deleteAnnoComp = true;

                annoLesionToolEntityList = this.packAnnoLesionToolEntityList(taskEntity.getId(), input.getAnnoSetting().getLesionList());
                List<AnnoComponentEntity> imageComponentEntityList = this.packImageComponentEntityList(taskEntity.getId(), input.getAnnoSetting().getLesionList());
                if (!ArrayUtil.isEmpty(imageComponentEntityList)) {
                    annoComponentEntityList.addAll(imageComponentEntityList);
                }
            }

            if (deleteAnnoLesionTool) {
                annoLesionToolDao.deleteByTaskId(taskEntity.getId());
            }

            if (deleteAnnoComp) {
                annoComponentDao.deleteByTaskId(taskEntity.getId());
            }

            if (!ArrayUtil.isEmpty(annoLesionToolEntityList)) {
                annoLesionToolDao.batchSave(annoLesionToolEntityList);
            }
            if (!ArrayUtil.isEmpty(annoComponentEntityList)) {
                annoComponentDao.batchSave(annoComponentEntityList);
            }
        }

        if (null != input.getDataSetting() && null != input.getDataSetting().getAnnoSeriesList()) {
            List<TaskSeriesEntity> taskSeriesEntityList = this.packTaskSeriesEntityList(taskEntity.getId(), input.getDataSetting().getAnnoSeriesList());

            taskSeriesDao.deleteByTaskId(taskEntity.getId());

            if (!ArrayUtil.isEmpty(taskSeriesEntityList)) {
                taskSeriesDao.batchSave(taskSeriesEntityList);
            }
        }

        if (null != input.getAnnoUserSetting() && null != input.getAnnoUserSetting().getAnnoUserList()) {
            List<TaskCompanyEntity> taskCompanyEntityList = this.packTaskCompanyEntityList(taskEntity.getId(), input.getAnnoUserSetting().getAnnoUserList());

            taskCompanyDao.deleteByTaskId(taskEntity.getId());
            taskUserDao.deleteByTaskId(taskEntity.getId());

            if (!ArrayUtil.isEmpty(taskCompanyEntityList)) {
                taskCompanyDao.batchSave(taskCompanyEntityList);
                taskCompanyEntityList = taskCompanyDao.findByTaskId(taskEntity.getId());
                List<TaskUserEntity> taskUserEntityList = this.packTaskUserEntityList(input.getAnnoUserSetting().getAnnoUserList(), taskCompanyEntityList);
                taskUserDao.batchSave(taskUserEntityList);
            }
        }
        return RespResult.ok();
    }

    @Transactional
    @Override
    public RespResult copy(Integer taskId) {
        TaskEntity oldTask = taskDao.findById(taskId);
        if (null == oldTask) {
            return RespResult.error("任务不存在");
        }
        // task、taskSeries、taskCompany、taskUser、anno_lesion_tool、anno_component

        List<TaskSeriesEntity> taskSeriesEntityList = taskSeriesDao.findByTaskId(taskId);

        List<TaskCompanyEntity> taskCompanyEntityList = taskCompanyDao.findByTaskId(taskId);

        List<TaskUserEntity> taskUserEntityList = taskUserDao.findByTaskId(taskId);

        List<AnnoLesionToolEntity> annoLesionToolEntityList = annoLesionToolDao.findByTaskId(taskId);

        List<AnnoComponentEntity> annoComponentEntityList = annoComponentDao.findByTaskId(taskId);


        TaskEntity newTask = new TaskEntity();
        BeanUtil.copy(oldTask, newTask);
        newTask.setName(oldTask.getName() + "-" + DateUtil.formatDate(new Date(), DateUtil.SEQ_FORMAT));
        if (newTask.getName().length() > 50) {
            newTask.setName("任务-" + DateUtil.formatDate(new Date(), DateUtil.SEQ_FORMAT));
        }
        newTask.setCreateUserId(userThreadLocal.getUser().getId());
        newTask.setStatus(TaskStatusEnum.NOT_START.getStatus());
        newTask.setId(null);
        newTask.setCreateTime(null);
        newTask.setUpdateTime(null);

        taskDao.insertSelective(newTask);

        Integer newTaskId = newTask.getId();

        List<TaskSeriesEntity> newTsList = taskSeriesEntityList.stream().map(x -> {
            TaskSeriesEntity newTs = new TaskSeriesEntity();
            BeanUtil.copy(x, newTs);
            newTs.setTaskId(newTaskId);
            newTs.setId(null);
            newTs.setCreateTime(null);
            newTs.setUpdateTime(null);
            return newTs;
        }).collect(Collectors.toList());

        List<AnnoLesionToolEntity> newAnnoLeisonToolList = annoLesionToolEntityList.stream().map(x -> {
            AnnoLesionToolEntity newAnnoLeisonTool = new AnnoLesionToolEntity();
            BeanUtil.copy(x, newAnnoLeisonTool);
            newAnnoLeisonTool.setTaskId(newTaskId);
            newAnnoLeisonTool.setId(null);
            newAnnoLeisonTool.setCreateTime(null);
            newAnnoLeisonTool.setUpdateTime(null);
            return newAnnoLeisonTool;
        }).collect(Collectors.toList());

        List<AnnoComponentEntity> newAnnoComponentList = annoComponentEntityList.stream().map(x -> {
            AnnoComponentEntity newAnnoComponent = new AnnoComponentEntity();
            BeanUtil.copy(x, newAnnoComponent);
            newAnnoComponent.setTaskId(newTaskId);
            newAnnoComponent.setId(null);
            newAnnoComponent.setCreateTime(null);
            newAnnoComponent.setUpdateTime(null);
            return newAnnoComponent;
        }).collect(Collectors.toList());

        List<TaskCompanyEntity> newTaskCompanyList = taskCompanyEntityList.stream().map(x -> {
            TaskCompanyEntity newTaskCompany = new TaskCompanyEntity();
            BeanUtil.copy(x, newTaskCompany);
            newTaskCompany.setTaskId(newTaskId);
            newTaskCompany.setId(null);
            newTaskCompany.setCreateTime(null);
            newTaskCompany.setUpdateTime(null);
            return newTaskCompany;
        }).collect(Collectors.toList());

        if (!ArrayUtil.isEmpty(newTaskCompanyList)) {
            taskCompanyDao.batchSave(newTaskCompanyList);
            newTaskCompanyList = taskCompanyDao.findByTaskId(newTaskId);
            Map<Integer, Integer> newTaskCompanyMap = newTaskCompanyList.stream().collect(Collectors.toMap(TaskCompanyEntity::getCompanyId, TaskCompanyEntity::getId));

            List<TaskUserEntity> newTaskUserList = taskUserEntityList.stream().map(x -> {
                TaskUserEntity newTaskUser = new TaskUserEntity();
                BeanUtil.copy(x, newTaskUser);
                newTaskUser.setTaskId(newTaskId);
                newTaskUser.setTaskCompanyId(newTaskCompanyMap.get(x.getCompanyId()));
                newTaskUser.setId(null);
                newTaskUser.setCreateTime(null);
                newTaskUser.setUpdateTime(null);
                return newTaskUser;
            }).collect(Collectors.toList());

            taskUserDao.batchSave(newTaskUserList);
        }

        if (!ArrayUtil.isEmpty(newTsList)) {
            taskSeriesDao.batchSave(newTsList);
        }

        if (!ArrayUtil.isEmpty(newAnnoLeisonToolList)) {
            annoLesionToolDao.batchSave(newAnnoLeisonToolList);
        }

        if (!ArrayUtil.isEmpty(newAnnoComponentList)) {
            annoComponentDao.batchSave(newAnnoComponentList);
        }

        return RespResult.ok();
    }

    @Override
    public List<TaskDto> query(List<Integer> ids) {
        if (ArrayUtil.isEmpty(ids)) {
            return new ArrayList<>();
        }
        List<TaskEntity> taskEntityList = taskDao.findByIds(ids.toArray(), null);
        return taskEntityList.stream().map(x -> this.packTask(x, null, null, null)).collect(Collectors.toList());
    }

    @Override
    public Boolean taskNameExisted(Integer id, String name) {
        TaskEntity cond = new TaskEntity();
        cond.setName(name);
        List<TaskEntity> taskListInDB = taskDao.findByCondition(cond, null);
        return taskListInDB.stream().filter(x -> !x.getId().equals(id) && x.getName().equals(name)).count() > 0;
    }

    @Override
    public List<AnnoSeriesDto> taskSeries(Integer id) {
        List<TaskSeriesEntity> tsList = taskSeriesDao.findByTaskId(id);
        if (ArrayUtil.isEmpty(tsList)) {
            return new ArrayList<>();
        }
        List<AnnoSeriesDto> seriesList = tsList.stream().map(x -> packAnnoSeriesDto(x)).collect(Collectors.toList());
        return seriesList;
    }

    private List<TaskSeriesEntity> packTaskSeriesEntityList(Integer taskId, List<AnnoSeriesDto> annoSeriesList) {
        if (ArrayUtil.isEmpty(annoSeriesList)) {
            return null;
        }
        return annoSeriesList.stream().map(x -> {
            String auxSeriesUid = null;
            String annoArea = null;
            if (!ArrayUtil.isEmpty(x.getAuxSeriesList())) {
                auxSeriesUid = StringUtils.joinWith(CommonConstant.DEFAULT_SEPARATOR, x.getAuxSeriesList().toArray());
            }
            if (!ArrayUtil.isEmpty(x.getAnnoAreaList())) {
                annoArea = JSONUtil.toJson(x.getAnnoAreaList());
            }

            return new TaskSeriesEntity(null, taskId, x.getSeriesUid(), x.getSeriesUid(), auxSeriesUid, annoArea);
        }).collect(Collectors.toList());
    }

    private List<TaskUserEntity> packTaskUserEntityList(List<AnnoUserDto> annoUserList, List<TaskCompanyEntity> taskCompanyEntityList) {
        if (ArrayUtil.isEmpty(annoUserList)) {
            return null;
        }
        Map<Integer, TaskCompanyEntity> taskCompanyMap = taskCompanyEntityList.stream().collect(Collectors.toMap(TaskCompanyEntity::getCompanyId, x -> x));
        return annoUserList.stream().map(x -> {
            return x.getUserIdList().stream().map(userId -> {
                return new TaskUserEntity(null, taskCompanyMap.get(x.getCompanyId()).getId(), x.getCompanyId(), taskCompanyMap.get(x.getCompanyId()).getTaskId(), userId);
            }).collect(Collectors.toList());
        }).flatMap(Collection::stream).collect(Collectors.toList());
    }

    private List<TaskCompanyEntity> packTaskCompanyEntityList(Integer taskId, List<AnnoUserDto> annoUserList) {
        if (ArrayUtil.isEmpty(annoUserList)) {
            return null;
        }
        return annoUserList.stream().map(x -> {
            return new TaskCompanyEntity(null, taskId, x.getCompanyId());
        }).collect(Collectors.toList());
    }

    private List<AnnoLesionToolEntity> packAnnoLesionToolEntityList(Integer taskId, List<LesionDto> lesionList) {
        if (ArrayUtil.isEmpty(lesionList)) {
            return null;
        }

        return lesionList.stream().map(x -> {
            return x.getToolValueList().stream().map(toolValue -> {
                return new AnnoLesionToolEntity(null, taskId, x.getLesionValue(), toolValue, x.getColor(), x.getBizType());
            }).collect(Collectors.toList());
        }).flatMap(Collection::stream).collect(Collectors.toList());
    }

    private List<AnnoComponentEntity> packImageComponentEntityList(Integer taskId, List<LesionDto> lesionList) {
        if (ArrayUtil.isEmpty(lesionList)) {
            return null;
        }

        AtomicInteger index = new AtomicInteger();
        return lesionList.stream().map(x -> {
            return x.getImageFcList().stream().map(y -> {
                int seq = index.addAndGet(10);
                return new AnnoComponentEntity(null, taskId, x.getLesionValue(), y.getFcId(), seq, null == y.getRequired() ? false : y.getRequired());
            }).collect(Collectors.toList());
        }).flatMap(Collection::stream).collect(Collectors.toList());
    }

    private List<AnnoComponentEntity> packSeriesComponentEntityList(Integer taskId, List<ComponentDto> seriesFcList) {
        if (ArrayUtil.isEmpty(seriesFcList)) {
            return null;
        }

        AtomicInteger index = new AtomicInteger();
        return seriesFcList.stream().map(x -> {
            int seq = index.addAndGet(10);
            return new AnnoComponentEntity(null, taskId, CommonConstant.EMPTY, x.getFcId(), seq, null == x.getRequired() ? false : x.getRequired());
        }).collect(Collectors.toList());
    }

    private TaskEntity packUserEntity(TaskCreateInDto input) {
        BasicSettingDto basicSetting = input.getBasicSetting();
        AnnoSettingDto annoSetting = input.getAnnoSetting();
        AnnoUserSettingDto annoUserSetting = input.getAnnoUserSetting();

        TaskEntity taskEntity = new TaskEntity();
        taskEntity.setName(null != basicSetting ? basicSetting.getName() : null);
        taskEntity.setStatus(TaskStatusEnum.NOT_START.getStatus());
        taskEntity.setCreateUserId(userThreadLocal.getUser().getId());
        taskEntity.setRemark(null != annoUserSetting ? annoUserSetting.getRemark() : null);
        taskEntity.setBeginDate(null != annoUserSetting ? annoUserSetting.getBeginDate() : null);
        taskEntity.setEndDate(null != annoUserSetting ? annoUserSetting.getEndDate() : null);
        taskEntity.setPubMethod(null != annoUserSetting ? annoUserSetting.getPubMethod() : null);
        taskEntity.setAssignMethod(null != annoUserSetting ? annoUserSetting.getAssignMethod() : null);
        taskEntity.setCrossNum(null != annoUserSetting ? (null == annoUserSetting.getCrossNum() || annoUserSetting.getCrossNum() < 1 ? 1 : annoUserSetting.getCrossNum()) : 1);
        taskEntity.setDepartment(null != basicSetting ? basicSetting.getDepartment() : null);
        taskEntity.setLabel(null != basicSetting ? basicSetting.getLabel() : null);
        taskEntity.setUses(null != basicSetting ? basicSetting.getUses() : null);
        taskEntity.setTarget(null != basicSetting ? basicSetting.getTarget() : null);
        taskEntity.setDefaultWindow(null != annoSetting ? annoSetting.getDefaultWindow() : null);
        taskEntity.setDiscardCode(null != basicSetting ? basicSetting.getDiscardCode() : null);
        taskEntity.setFindings(null != annoSetting ? annoSetting.getFindings() : null);
        taskEntity.setDiagnosis(null != annoSetting ? annoSetting.getDiagnosis() : null);
        taskEntity.setShowReport(null != annoSetting ? annoSetting.getShowReport() : null);
        taskEntity.setShowYay(null != annoSetting ? annoSetting.getShowYay() : null);
        taskEntity.setImageLayout(null != annoSetting ? annoSetting.getImageLayout() : null);

        return taskEntity;

    }

    private TaskDetailDto packTaskDetail(TaskEntity taskEntity, List<TaskCompanyEntity> taskCompanyEntityList, List<TaskUserEntity> taskUserEntityList, List<AnnoLesionToolEntity> annoLesionToolEntityList, List<AnnoComponentEntity> annoComponentEntityList, List<TaskSeriesEntity> tsList) {

        TaskDetailDto taskDetail = new TaskDetailDto();
        BeanUtil.copy(taskEntity, taskDetail);

        List<ComponentDto> seriesFcList = null;

        final List<LesionDto> lesionList = new ArrayList<>();

        List<AnnoUserDto> annoUserList = null;

        List<AnnoSeriesDto> seriesList = null;

        if (!ArrayUtil.isEmpty(taskCompanyEntityList)) {
            annoUserList = taskCompanyEntityList.stream().map(taskCompany -> {
                AnnoUserDto annoUser = new AnnoUserDto();
                annoUser.setCompanyId(taskCompany.getCompanyId());

                if (!ArrayUtil.isEmpty(taskUserEntityList)) {
                    List<Integer> userIdList = taskUserEntityList.stream().filter(x -> x.getTaskCompanyId().equals(taskCompany.getId())).map(TaskUserEntity::getUserId).distinct().collect(Collectors.toList());
                    annoUser.setUserIdList(userIdList);
                }
                return annoUser;
            }).collect(Collectors.toList());
        }

        if (!ArrayUtil.isEmpty(annoComponentEntityList)) {
            seriesFcList = annoComponentEntityList.stream().filter(x -> StringUtils.isEmpty(x.getLesion())).sorted(Comparator.comparing(AnnoComponentEntity::getSeq)).map(x -> {
                return new ComponentDto(x.getComponentId(), x.getRequired());
            }).collect(Collectors.toList());
        }

        if (!ArrayUtil.isEmpty(annoLesionToolEntityList)) {
            annoLesionToolEntityList.stream().collect(Collectors.groupingBy(AnnoLesionToolEntity::getLesion)).forEach((key, valueList) -> {
                List<String> toolList = valueList.stream().map(AnnoLesionToolEntity::getTool).collect(Collectors.toList());
                List<ComponentDto> imageFcList = null;
                if (!ArrayUtil.isEmpty(annoComponentEntityList)) {
                    imageFcList = annoComponentEntityList.stream().filter(x -> key.equals(x.getLesion())).sorted(Comparator.comparing(AnnoComponentEntity::getSeq)).map(x -> {
                        return new ComponentDto(x.getComponentId(), x.getRequired());
                    }).collect(Collectors.toList());
                }
                LesionDto lesion = new LesionDto(key, valueList.get(0).getLesionColor(), toolList, imageFcList, valueList.get(0).getBizType());
                lesionList.add(lesion);
            });
        }

        if (!ArrayUtil.isEmpty(tsList)) {
            seriesList = tsList.stream().map(x -> packAnnoSeriesDto(x)).collect(Collectors.toList());
        }

        taskDetail.setSeriesList(seriesList);
        taskDetail.setSeriesFcList(seriesFcList);
        taskDetail.setLesionList(lesionList);
        taskDetail.setAnnoUserIdList(annoUserList);
        return taskDetail;

    }

    private TaskDto packTask(TaskEntity taskEntity, List<TaskCompanyEntity> taskCompanyList, Integer seriesCount, TaskAnnoCountInfoPo annoCountInfo) {

        TaskDto task = new TaskDto();
        BeanUtil.copy(taskEntity, task);

        List<Integer> companyIdList = null;

        if (!ArrayUtil.isEmpty(taskCompanyList)) {
            companyIdList = taskCompanyList.stream().map(TaskCompanyEntity::getCompanyId).distinct().collect(Collectors.toList());
        }

        Integer arCountOfStatus = annoCountInfo == null ? 0 : annoCountInfo.getArCountOfStatus();
        Integer lrCountOfStatus = annoCountInfo == null ? 0 : annoCountInfo.getLrCountOfStatus();
        seriesCount = null == seriesCount ? 0 : seriesCount;

        task.setCompanyIdList(companyIdList);
        task.setSeriesCount(seriesCount);
        task.setSubmitedSeriesCount(arCountOfStatus);
        task.setUnSubmitedSeriesCount((task.getCrossNum() * seriesCount) - arCountOfStatus);
        task.setIarCount(lrCountOfStatus);
        return task;
    }

    private void triggerDownloadImage(TaskEntity task) {
        ImageLayoutEnum layoutEnum = ImageLayoutEnum.getEnumByValue(task.getImageLayout());
        if (ImageLayoutEnum.MPATHOLOGYPR_ANNO != layoutEnum && ImageLayoutEnum.VIDEO_ANNO != layoutEnum) {
            return;
        }
        List<TaskSeriesEntity> taskSeriesList = taskSeriesDao.findByTaskId(task.getId());

        List<String> seriesUids = taskSeriesList.stream().map(TaskSeriesEntity::getSeriesUid).distinct().collect(Collectors.toList());

        if (ArrayUtil.isEmpty(seriesUids)) {
            return;
        }

        RespResult<Map<String, List<DwhImageDto>>> imageQuery = dwhImageFeign.imageQuery(new DwhImageQueryInDto(seriesUids));
        if (!imageQuery._isOk()) {
            throw new CustomBizException("查询数仓影像信息失败");
        }

        FileHandlerBizTypeEnum bizTypeEnum;
        switch (layoutEnum) {
            case MPATHOLOGYPR_ANNO:
                bizTypeEnum = FileHandlerBizTypeEnum.BIG_IMAGE_DOWNLOAD;
                break;
            case VIDEO_ANNO:
                bizTypeEnum = FileHandlerBizTypeEnum.VIDEO_DOWNLOAD;
                break;
            default:
                return;
        }

        List<AnnoFileHandlerInfoEntity> fileHandlerInfos2Save = seriesUids.stream().map(seriesUid -> {
            List<DwhImageDto> dwhImageDtos = imageQuery.getData().get(seriesUid);
            if (ArrayUtil.isEmpty(dwhImageDtos)) {
                throw new CustomBizException("未查询到影像信息! series: " + seriesUid);
            }
            String targetFilePath = fileHandlerInfoService.getTargetFilePath(bizTypeEnum, task.getId(), seriesUid, dwhImageDtos.get(0).getPath());
            return new AnnoFileHandlerInfoEntity(null, task.getId(), seriesUid, bizTypeEnum.getBizType(), ProcessStatusEnum.NOT_START.getStatus(), targetFilePath, null);
        }).collect(Collectors.toList());

        fileHandlerInfoDao.batchSave(fileHandlerInfos2Save);

        List<AnnoFileHandlerInfoEntity> fileHandlerInfoinDB = fileHandlerInfoDao.findByTaskId(task.getId());

        fileHandlerInfoinDB.forEach(x -> fileHandlerProduser.send(x.getId()));
    }

    private AnnoSeriesDto packAnnoSeriesDto(TaskSeriesEntity ts) {
        AnnoSeriesDto annoSeries = new AnnoSeriesDto();
        annoSeries.setSeriesUid(ts.getSeriesUid());
        if (StringUtils.isNotEmpty(ts.getAuxSeriesUid())) {
            annoSeries.setAuxSeriesList(Arrays.asList(ts.getAuxSeriesUid().split(CommonConstant.DEFAULT_SEPARATOR)));
        }
        if (StringUtils.isNotEmpty(ts.getAnnoArea())) {
            List<String> annoAreaList = new ArrayList<>();
            Iterator<JsonElement> iterator = JSONUtil.parseArray(ts.getAnnoArea()).iterator();
            while (iterator.hasNext()) {
                String str = iterator.next().getAsString();
                annoAreaList.add(str);
            }
            annoSeries.setAnnoAreaList(annoAreaList);
        }
        return annoSeries;
    }

    private RespResult validImageTransfer(TaskEntity task) {
        ImageLayoutEnum layoutEnum = ImageLayoutEnum.getEnumByValue(task.getImageLayout());
        if (ImageLayoutEnum.VIDEO_ANNO != layoutEnum) {
            return RespResult.ok();
        }
        List<TaskSeriesEntity> taskSeriesList = taskSeriesDao.findByTaskId(task.getId());
        if (ArrayUtil.isEmpty(taskSeriesList)) {
            return RespResult.secByError(RespCodeEnum.ERROR.getCode(), "任务未导入序列");
        }

        List<String> seriesUids = taskSeriesList.stream().map(TaskSeriesEntity::getSeriesUid).distinct().collect(Collectors.toList());

        ImageQueryInDto imageQueryInDto = new ImageQueryInDto(seriesUids, ImageGroupTypeEnum.SERIES_IMAGE_TRANSFER, Arrays.asList(ImageTransferModeEnum.VIDEO_FRAME_EXTRACT), null, false);
        RespResult<List<ImageInfoOutDto>> respResult = imageFeign.query(imageQueryInDto);
        if (!respResult._isOk()) {
            return RespResult.secByError(RespCodeEnum.ERROR.getCode(), "查询标注影像信息失败");
        }
        List<ImageInfoOutDto> data = respResult.getData();
        if (ArrayUtil.isEmpty(data)) {
            return RespResult.secByError(RespCodeEnum.ERROR.getCode(), "影像转换未完成");
        }

        List<String> transferedSeriesList = data.stream().map(x -> x.getImageInfo().getGroup()).collect(Collectors.toList());
        String seriesUid = seriesUids.stream().filter(x -> !transferedSeriesList.contains(x)).findFirst().orElse(null);
        if (null != seriesUid) {
            return RespResult.secByError(RespCodeEnum.ERROR.getCode(), "影像转换未完成! series :" + seriesUid);
        }

        return RespResult.ok();
    }
}
